package it.antonio.ilpizze.servlet.core;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Reflection {
	public static List<Method> methodsWithAnnotation(Class<?> clazz, Class<? extends Annotation> annotation){
		final List<Method> methods = new ArrayList<Method>();
	    Class<?> classToScan = clazz;
	    while (classToScan !=null && classToScan != Object.class) { 
	        for (Method method : classToScan.getDeclaredMethods()) {
	            if (method.isAnnotationPresent(annotation)) {
	            	boolean add = true;
	            	for(Method m: methods){
	            		if (method.getName().equals(m.getName()) &&	Arrays.equals(method.getParameterTypes(), m.getParameterTypes())) {
	            			add = false;
							break;
						}
	            	}
	                if(add){
	                	methods.add(method);
	                }
	            }
	        }
	        classToScan = classToScan.getSuperclass();
	    }
	    return methods;
	}
	
	
	public static class ReflectionException extends RuntimeException{

		private static final long serialVersionUID = 1L;

		public ReflectionException(Throwable arg0) {
			super(arg0);
		}
		
		
		
	}

	public static boolean isSetter(Method method) {
		return method.getName().startsWith("set") && method.getParameterTypes().length == 1;
	}
	public static String getPropertyName(Method method) {
		String methodName = method.getName();
		String property = methodName.substring(3);
		return property.substring(0, 1).toLowerCase() + property.substring(1, property.length());
	}

	public static Object newInstance(Class<?> clazz) {
		try {
			return clazz.newInstance();
		} catch (InstantiationException e) {
			throw new ReflectionException(e);
		} catch (IllegalAccessException e) {
			throw new ReflectionException(e);
		}
	}
	public static Object invoke(Object instance, Method method, Object... values) {
		try {
			return method.invoke(instance, values);
		} catch (IllegalArgumentException e) {
			throw new ReflectionException(e);
		} catch (IllegalAccessException e) {
			throw new ReflectionException(e);
		} catch (InvocationTargetException e) {
			throw new ReflectionException(e);
		}
	}
	
	public static List<Field> fields(Class<?> clazz) {
		final List<Field> fields = new ArrayList<Field>();
	    Class<?> classToScan = clazz;
	    while (classToScan !=null && classToScan != Object.class) { 
	        for (Field field : classToScan.getDeclaredFields()) {
	            fields.add(field);
	        }
	        classToScan = classToScan.getSuperclass();
	    }
	    return fields;
	}
	public static Object get(Object value, Field field) {
		try {
			return field.get(value);
		} catch (IllegalArgumentException e) {
			throw new ReflectionException(e);
		} catch (IllegalAccessException e) {
			throw new ReflectionException(e);
		}
	}


	
}
